home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Networking / Network Watch (DMZ) v1.5 / sources / dMZAT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-25  |  31.8 KB  |  1,281 lines  |  [TEXT/MPS ]

  1. /*
  2. #-------------------------------------------------------------------------------------------
  3. #
  4. #    Program:    < DMZ 1.3 >
  5. #    File:        < dmzAT.c >
  6. #    
  7. #    by Pete Helme
  8. #    of <Apple Macintosh Developer Technical Support - or wheverever>
  9. #
  10. #    Modification History
  11. #    5/23/94     rrk    Implemented Steve Falkenburg's changes for compatibility with PPC
  12. #                    This code was compile with MPW 3.3.1 and Think C 7.0 using
  13. #                    Universal headers
  14. #    9/20/92  rrk    Change nbp type from "\pnot Anything" to "\pEcho Type".  Set socket
  15. #                    address to 4 as opposed to leaving it at 0.
  16. #    3/25/92     rrk     Fixed program so that if no zones are selected and the "no zones (*)"
  17. #                    item selected, the local zone is searched.
  18. #    3/25/92     rrk     Implemented J. Luther's socket listener, replacing Pete's listener
  19. #    3/25/92  rrk    Updated code to work with Think C 5.0.
  20. #
  21. #    Copyright © 1990 Apple Computer, Inc.
  22. #    All rights reserved.
  23. #    
  24. #-------------------------------------------------------------------------------------------
  25. */
  26.  
  27. /*
  28.  *     dmz Sample AppleTalk Stuff
  29.  *
  30.  *    This unit handles all AppleTalk functions for dmz.  Including: AppleTalk 
  31.  *    presence verification and activation, socket opening, set self send enabling  
  32.  *    name binding protocol registration, bridge presence verification, 
  33.  *    zone name lookups, hot dish zapper, name removal, socket closing & no weeds.
  34.  *
  35.  */
  36.  
  37. #include    "dmz.h"
  38.  
  39.  
  40. /* globals from afar */
  41. /* out main dialog */
  42. extern DialogPtr     gLookupDialog;
  43. extern DialogPtr     gMyDialog;
  44. extern char         gNameGlob[34];
  45. extern SysEnvRec    GMAC;
  46. extern myATQEntry    gATQEntry;
  47. extern short        gATalkFlags;
  48.  
  49. /* and others */
  50. /* 
  51.  *     gBuffers is used in the by the socket listener code set up in the doEcho 
  52.  *     function.  The socket listener uses these buffers to save received packets
  53.  *    until they can be processed.
  54.  */
  55. PacketBuffer    gBuffers[kNumBuffers];    /* set up by InitEchoBuffers */
  56.  
  57. /* 
  58.  *     gFreeQ and gUsedQ as their names imply, are used to track whether gBuffers 
  59.  *  packet record buffers are available for use or have been filled in by the 
  60.  *  socket listener and are available for processing.
  61.  */
  62. QHdr                gFreeQ, gUsedQ;                /* set up by InitEchoBuffers */
  63. Handle                 gSockCodeHndl = nil;         /* handle to socket listener code resource */
  64.  
  65.  
  66. Ptr                 gBuffPtr = nil;
  67. myMPPParamBlock     *gPBLkUP = nil;
  68. Boolean             gUpdateListFlag;
  69. Boolean             gLookupFinished;
  70. NamesTableEntry     gMyNTE;
  71. AddrBlock             gTheBridgeAddress;
  72. Boolean                gHasPhase2 = false;
  73. NamesTableEntry     gLookupNTE;    
  74. char                gOrigSelfSend;
  75.  
  76. Ptr                    GTHEVBLPTR;
  77. Ptr                    GTHETASKPTR;
  78.  
  79. /*     
  80.  *    Inline routines for saving & restoring A5 in our PLookupName completion routine.
  81.  *
  82.  *    move.l    a5, -(a7)
  83.  *    move.l    $FFFC(a0), a5    ; -4(A0)
  84.  *
  85.  */
  86. #ifndef powerc
  87. pascal void saveThatA5(void)
  88.     = {0x2f0d, 0x2a68, 0xFFFC};
  89. #endif
  90.     
  91. /*
  92.  *    move.l    (a7)+, a5
  93.  */
  94. #ifndef powerc
  95. pascal void restoreThatA5(void)
  96.     = {0x2A5F};
  97. #endif
  98.     
  99.     
  100. /*     
  101.  *    Boring Pascal string concat routine.  Skip ahead a bit.
  102.  */
  103. unsigned char *Pstrcat(unsigned char *s, unsigned char *t)
  104. {
  105.     long     i, length;
  106.     unsigned char     *p;
  107.     
  108.     length = *t;
  109.     p = s + *s + 1;
  110.     t++;
  111.     
  112.     for(i=0;i<length;i++) 
  113.         *p++ = *t++;
  114.  
  115.     *s += length;
  116.     return s;
  117. }
  118.  
  119. /*     
  120.  *    Returns length of pascal type strings.  Again, quite boring.
  121.  */
  122. unsigned char PStrLen(unsigned char *e)
  123. {
  124.     unsigned char length;
  125.     
  126.     length = *e;
  127.     return(length);
  128. }
  129.  
  130. /*
  131.  * Returns true if two Pascal strings are the same, false otherwise.
  132.  */
  133.  
  134. Boolean    PStrComp(unsigned char *str1, unsigned char *str2)
  135.  
  136. {
  137.     unsigned char    i;
  138.     unsigned char    j;
  139.     Boolean            ok;
  140.     
  141.     if (*str1 != *str2)
  142.         return(false);                    /* strings are of unequal length */
  143.     
  144.     i = *str1;
  145.     ok = true;                            /* assume strings are the same */
  146.     j = 0;
  147.     for (j = 0; j < i; j++) {
  148.         if (*(++str1) != *(++str2))
  149.             return(false);
  150.     }
  151.     return(true);
  152. }        
  153.  
  154. /*     
  155.  *     Removes a specific NBP Lookup from queue if one pending.  Why?  So we don't hurt ourselves.
  156.  *    
  157.  */
  158. void killLookups(void)
  159. {
  160.     MPPParamBlock     killPB;
  161.     OSErr             resultCode;
  162.  
  163.     if(gPBLkUP->myMPP.MPPioResult == 1) {
  164.         killPB.NBPnKillQEl = (Ptr)&gPBLkUP->myMPP.MPP.qLink;
  165.         resultCode = PKillNBP(&killPB, false);
  166.         }
  167. }
  168.  
  169. /*     
  170.  *    Removes our name and ATP socket.
  171.  */
  172. void removeMyNameAndSocket(void)
  173. {
  174.     MPPParamBlock     pb;
  175.  
  176.     if (TstNameRegisteredFlag(gATalkFlags)) 
  177.     {    
  178.         if (OpenTransportActive())
  179.         {
  180.             OTDeleteMyName();
  181.                 // dont clear the kNameRegistered flag here since it will get cleared by the Mapper Handler
  182.         }
  183.         else
  184.         {
  185.             pb.NBPentityPtr = (Ptr)&gMyNTE.nt.entityData[0];
  186.             PRemoveName(&pb, false);
  187.             ClrNameRegisteredFlag(gATalkFlags);
  188.         }
  189.     }
  190. }
  191.  
  192. /*     
  193.  *    Shutdown our AppleTalk usage.  Disposes of name lookup buffers.  
  194.  *    Calls to remove our NBP name.    
  195.  */
  196. void closeUpOurAppleTalk(void)
  197. {
  198.     Size        listenerSize;
  199.     
  200.     killLookups();
  201.     if (OpenTransportActive())
  202.         CleanupOTServices();
  203.     
  204.     if(gBuffPtr != 0L)
  205.         DisposePtr(gBuffPtr);
  206.     if(gPBLkUP != 0L)
  207.         DisposePtr((Ptr) gPBLkUP);
  208.  
  209.     if (TstSocketBuffsHeldFlag(gATalkFlags))    /* ckeck if socket buffer held due to VM */
  210.     {
  211.         UnholdMemory(&gBuffers, sizeof(gBuffers));
  212.         UnholdMemory(&gFreeQ, sizeof(QHdr));
  213.         UnholdMemory(&gUsedQ, sizeof(QHdr));
  214.         ClrSocketBuffsHeldFlag(gATalkFlags);
  215.     }
  216.  
  217.     if (TstListenerHeldFlag(gATalkFlags))         /* ckeck if socket listener held due to VM */
  218.     {
  219.         listenerSize = GetHandleSize(gSockCodeHndl);
  220.         UnholdMemory(*gSockCodeHndl, listenerSize);
  221.         ClrListenerHeldFlag(gATalkFlags);
  222.     }        
  223.  
  224.     if (TstATQInstalledFlag(gATalkFlags))        /* check if ATalk Trans queue installed */
  225.     {
  226.         LAPRmvATQ((ATQEntry*)&gATQEntry);
  227.         ClrATQInstalledFlag(gATalkFlags);
  228.     }
  229.  
  230.     removeMyNameAndSocket();
  231. }
  232.     
  233. /*     
  234.  *    Registers name from the System's STR -16413, the Flagship (Macintosh Name) resource under
  235.      System 7.x (what appears in the Sharing Setup control panel), or STR -16096 resource if 
  236.      under System 6.0.x. (what is usually seen in the Chooser) 
  237.  */
  238.  
  239. void registerMyName()
  240. {
  241.     MPPParamBlock     pb;
  242.     OSErr             err;
  243.     long             byteCount;
  244.     StringHandle    userName;
  245.     
  246.     if (OpenTransportActive())
  247.         OTRegisterMyName();
  248.     else
  249.     {
  250.         byteCount = 0L;
  251.     
  252.         /* this grabs the name from the Macintosh Name String if it is found under System 7.x
  253.            or the user's Chooser name string if 6.0.x or earlier.  If there is nothing
  254.         there we'll substitute our own name */
  255.         userName = GetString(kFlagshipNameResourceID);
  256.         if (**userName == 0) 
  257.         {
  258.             userName = GetString(kMachineNameResourceID); 
  259.             if(**userName == 0)
  260.             {
  261.                 userName = (StringHandle)NewHandle(sizeof(Str32));
  262.                 if (userName)
  263.                     BlockMove("\pYour name here", *userName, 15L);
  264.                 else
  265.                     userName = nil;
  266.             }
  267.         }
  268.         if (userName)
  269.         {
  270.             NBPSetNTE((Ptr)&gMyNTE, (ConstStr32Param)*userName, (ConstStr32Param)kEchoType, (ConstStr32Param)"\p*", gMyNTE.nt.nteAddress.aSocket);
  271.         
  272.             pb.NBPinterval = 2;
  273.             pb.NBPcount = 3;
  274.         
  275.             /* wants pointer to NamesTableEntry NOT entityName! */
  276.             pb.NBPntQElPtr = (Ptr)&gMyNTE;
  277.             pb.NBPverifyFlag = 1; /* verify that we be the only one! */
  278.         
  279.             err = PRegisterName(&pb, false);
  280.             if (err == noErr) 
  281.             {
  282.                 SetNameRegisteredFlag(gATalkFlags);
  283.                 ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = &gMyNTE;
  284.             }
  285.             /* if error occured registering name, there is no reason to 
  286.              * abort the program 
  287.              */
  288.         }
  289.         // if the handle couldn't be allocated, go ahead anyway.
  290.     }
  291. }
  292.  
  293.     
  294. /* 
  295.  *    Enables AppleTalk option to talk to one's own node. ONLY for SE's, //'s or MacPluses with AppleTalk driver of v48 or greater!! 
  296.  *  Saves original state in the global gOrigSelfSend.
  297.  */
  298. void enableSetSelfSend() 
  299. {
  300.  
  301.     SetSelfparms    pb;
  302.     OSErr             err;
  303.  
  304.     pb.newSelfFlag = true;  /* set self send option */
  305.     err = PSetSelfSend((MPPPBPtr) &pb, false);
  306.     if (err == noErr)
  307.         gOrigSelfSend = pb.oldSelfFlag;
  308. }
  309.     
  310.  
  311. /* 
  312.  *    restores AppleTalk option to talk to one's own node. ONLY for SE's, //'s or MacPluses with AppleTalk driver of v48 or greater!! 
  313.  *  uses value in the global gOrigSelfSend.
  314.  */
  315. void restoreSetSelfSend() 
  316. {
  317.  
  318.     SetSelfparms    pb;
  319.  
  320.     pb.newSelfFlag = gOrigSelfSend;  /* set self send option to saved value*/
  321.     PSetSelfSend((MPPPBPtr) &pb, false);
  322. }
  323.     
  324.  
  325. /*    
  326.  *    Checks to see if we are running AppleTalk Phase 2 compatible drivers.
  327.  */
  328. void phase2Check()
  329. {
  330.     if(GMAC.atDrvrVersNum >= 53) 
  331.         gHasPhase2 = true;
  332.     else 
  333.         HideDialogItem(gLookupDialog, kPhase2Item);
  334. }
  335.  
  336.  
  337. /*    
  338.  *    Opens up AppleTalk.  Opens our ATP socket.  Initializes our flag
  339.  *  which indicate the current state of AppleTalk.  If AppleTalk is not
  340.  *  open, then we do not want to display the zone list.
  341.  */
  342. void InitAppleTalkVars()
  343. {
  344.     extern void     getTheZoneList();
  345.     OSErr            err;
  346.     
  347.     /* 
  348.      *    buffer necessary for async name lookups 
  349.      *  this routine can be called from the TransQueue
  350.      */
  351.     if (gPBLkUP == nil)
  352.         gPBLkUP = (myMPPParamBlock *) NewPtr(sizeof(myMPPParamBlock));
  353.     if (gBuffPtr == nil)
  354.         gBuffPtr = NewPtr(kLookupBufSize);
  355.     gMyNTE.nt.nteAddress.aSocket = kEchoSocket;
  356.     
  357.     if ((gPBLkUP == nil) || (gBuffPtr == nil))
  358.         BigBadError("\pError allocating lookup memory - Aborting program");
  359.     else
  360.     {
  361.         if (IsMPPOpen())
  362.         {
  363.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkActive = true;
  364.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkStatusChanged = false;
  365.             ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = nil;
  366.             if (ActivateOpenTransport() != noErr)  //         
  367.                 phase2Check();
  368.             enableSetSelfSend();
  369.             getTheZoneList();
  370.             registerMyName();
  371.         
  372.             /* call socket listener init code */
  373.             err = InitEchoBuffers();
  374.             if (err != noErr)
  375.             {
  376.                 BigBadError("\pError initializing Echo Buffers");
  377.             }
  378.         }
  379.         else
  380.         {
  381.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkActive = false;
  382.             ((dmzEntryPtr) *(gATQEntry.globs))->atalkStatusChanged = false;
  383.             ((dmzEntryPtr) *(gATQEntry.globs))->dmzNTEPtr = nil;
  384.             tellUserNoZones();        // which tells the user that AppleTalk is off
  385.         }
  386.         
  387.     }
  388. }
  389.         
  390.  
  391.  
  392. /*
  393.  *    in order for us to use the standard qsort() algorithm, our data must be alligned in
  394.  *    an orderly fashion with a set offset from each data entry. This routine takes care of
  395.  *    that through simple _BlockMove manipulations.
  396.  */
  397. void addToUnpackedBuffer(Ptr oldBuffer, Ptr newBuffer, short numGot, short total)
  398. {
  399.     long    oldIndex = 0L, newIndex = 0L;
  400.     short    i;
  401.     
  402.     for(i=0;i<numGot;i++) {
  403.         if (((newIndex + total) * 33) > (kMaxZoneBuffSize - 32))
  404.             break;    // protect against potentially writing beyond the buffer
  405.             
  406.         BlockMove((Ptr)oldBuffer+oldIndex, (Ptr)newBuffer+(newIndex+total)*33, 33L);
  407.         oldIndex += (char)((Ptr)oldBuffer+oldIndex)[0]+1L;
  408.         newIndex += 1;
  409.         }
  410. }
  411.  
  412.  
  413. /*
  414.  *    return our local zone name the old fashioned way.  We could easily use the 
  415.  *  GetMyZone function, which would be simpler
  416.  */
  417. void getMyZone(char *myZoneBuffer)
  418. {
  419.     BDSElement         myZoneBDS;
  420.     ATPParamBlock     ZonePB;
  421.     
  422.         // check whether Open Transport is active and use it to get MyZone
  423.     if (OpenTransportActive())
  424.     {
  425.         DoOTGetMyZone(myZoneBuffer);
  426.     }
  427.     else
  428.     {
  429.         myZoneBDS.buffSize = 33;
  430.         myZoneBDS.buffPtr = (Ptr) myZoneBuffer;
  431.         myZoneBDS.dataSize = 0;
  432.         myZoneBDS.userBytes = 0;
  433.     
  434.         ZonePB.ATPatpFlags = 0;
  435.         ZonePB.ATPioCompletion = 0L; 
  436.         ZonePB.ATPuserData = 0;    /* ATP user data */
  437.         ZonePB.ATPaddrBlock = gTheBridgeAddress;
  438.         ZonePB.ATPreqLength = 0;
  439.         ZonePB.ATPreqPointer = 0L;
  440.         ZonePB.ATPbdsPointer = (Ptr)&myZoneBDS;
  441.         ZonePB.ATPnumOfBuffs = 1;
  442.         ZonePB.ATPtimeOutVal = 3;
  443.         ZonePB.ATPretryCount = 3;
  444.     
  445.         /*
  446.          *    make sure to NIL this field out so bottom three bytes are 0
  447.          */
  448.         ZonePB.ATPuserData = 0x07000000;        /* GetLocalZone = 7 */
  449.             
  450.         if(PSendRequest(&ZonePB, false) != noErr)
  451.             myZoneBuffer[0] = 0;
  452.     }
  453. }
  454.  
  455.  
  456. void doGetZoneListPrePh2()
  457. {            
  458.     BDSElement             myZoneBDS;
  459.     ATPParamBlock         ZonePB;
  460.     OSErr                 theResult;
  461.     long                 tempUserData;
  462.     Ptr                 theBufferPtr;
  463.     short                 zIndex, zoneCallType;
  464.     short                 NumZonesGot = 0, totalZones = 0;
  465.     Boolean             DontGetMoreZones;
  466.     extern ListHandle    zonesList;
  467.     Ptr                    returnBuffer;
  468.     
  469.     zIndex = 1;
  470.     zoneCallType = _GetZoneList;
  471.     DontGetMoreZones = false;
  472.     
  473.     returnBuffer = NewPtr(kMaxZoneBuffSize); /* set to max SInt16 */
  474.     
  475.     theBufferPtr = NewPtr(578); /* size of BDS */
  476.     if(MemError()==noErr) {
  477.         while(!DontGetMoreZones) {
  478.             zIndex += NumZonesGot;            /* index count. 1 for start */
  479.             myZoneBDS.buffSize = 578;
  480.             myZoneBDS.buffPtr = theBufferPtr;
  481.             myZoneBDS.dataSize = 0;
  482.             myZoneBDS.userBytes = 0;
  483.     
  484.             ZonePB.ATPatpFlags = 0;
  485.             ZonePB.ATPioCompletion = 0L; 
  486.             ZonePB.ATPuserData = 0;    /* ATP user data */
  487.             ZonePB.ATPaddrBlock = gTheBridgeAddress;
  488.             ZonePB.ATPreqLength = 0;
  489.             ZonePB.ATPreqPointer = 0L;
  490.             ZonePB.ATPbdsPointer = (Ptr)&myZoneBDS;
  491.             ZonePB.ATPnumOfBuffs = 1;
  492.             ZonePB.ATPtimeOutVal = 4;
  493.             ZonePB.ATPretryCount = 4;
  494.             
  495.             BlockMove((Ptr) &zoneCallType + 1, (Ptr) &tempUserData, 1L);
  496.             BlockMove((Ptr) &zIndex, (Ptr)&tempUserData + 2, 2L);
  497.     
  498.             ZonePB.ATPuserData = tempUserData;
  499.                 
  500.             theResult = PSendRequest(&ZonePB, false);
  501.     
  502.             if(theResult == noErr) {            
  503.                 tempUserData = myZoneBDS.userBytes;
  504.                 BlockMove((Ptr) &tempUserData, (Ptr) &DontGetMoreZones, 1); /* the highbyte will be nonzero if its the last packet of zones */
  505.                 BlockMove((Ptr)&tempUserData + 2, (Ptr) &NumZonesGot, 2);
  506.  
  507.                 addToUnpackedBuffer(myZoneBDS.buffPtr, returnBuffer, NumZonesGot, totalZones);    
  508.                 
  509.                 totalZones += NumZonesGot;
  510.                 }
  511.             }
  512.         
  513.         SetZoneCells(returnBuffer, totalZones);
  514.  
  515.         DisposePtr(theBufferPtr);
  516.         DisposePtr(returnBuffer);
  517.         }
  518.     
  519. }
  520.  
  521. /* 
  522.  *    zonesPresent is used to determine whether zones are present by checking the 
  523.  *    existence of a router.  In previous releases, we use to check that the
  524.  *    network number was non-zero.  Under ARA, the network number could be zero
  525.  *    however, the bridge node ID might not be.  This correction was implemented
  526.  *  by Pete Lovell, GE Information Services
  527.  */
  528. Boolean zonesPresent() 
  529. {
  530.     short         theBridgeNode = 0;
  531.     short        theBridgeNet = 0;
  532.     short        node;
  533.     OSErr        err;
  534.  
  535.     if (!OpenTransportActive())
  536.     {    // open transport is not active - do things the traditional method
  537.         err = GetNodeAddress(&node, &theBridgeNet);
  538.         /* 
  539.          * On an extended network, this node ID is simply a flag.  Use _GetAppletalkInfo to get the
  540.          * real 24 bit address of the last router heard from.
  541.          */
  542.         theBridgeNode = GetBridgeAddress();
  543.         
  544.         if (theBridgeNode != 0)
  545.         {
  546.             gTheBridgeAddress.aNet = theBridgeNet;
  547.             gTheBridgeAddress.aNode = theBridgeNode;
  548.             gTheBridgeAddress.aSocket = kBridgeSocket;
  549.             return true;
  550.         }
  551.         else
  552.             return false;
  553.     }
  554.     else
  555.     {        // open transport is active
  556.         GetBridgeAddressFromOT(&gTheBridgeAddress);
  557.         if (gTheBridgeAddress.aNode != 0)
  558.             return true;
  559.         else
  560.             return false;
  561.     }
  562. }
  563.  
  564.     
  565. void setItemString(DialogPtr whichDialog, short whichItem, Str255 str)
  566. {
  567.     Rect         r;
  568.     short         kind;
  569.     Handle         h;
  570.     
  571.     GetDialogItem(whichDialog, whichItem, &kind, &h, &r);
  572.     SetDialogItemText(h, str);
  573. }
  574.      
  575.  
  576. /* 
  577.  *    getTheZoneList is used to call the appropriate method to get the
  578.  *    zone list - assuming that zones are present.
  579.  */
  580. void getTheZoneList()
  581. {
  582.     StartAnimatedCursors(kSpinEvery5Ticks, 15);
  583.     if (zonesPresent()) 
  584.     {
  585.         if (OpenTransportActive() == false)
  586.         {
  587.             /*
  588.              * if AppleTalk Phase 2 is present (>= v53) then use new call
  589.              */
  590.             if(gHasPhase2)
  591.                 doGetZoneListPhs2();
  592.             else
  593.                 doGetZoneListPrePh2();
  594.         }
  595.         else
  596.             DoOTGetZoneList();
  597.     }
  598.     else 
  599.     { 
  600.         /* 
  601.          *    no zones.  inform user of this. 
  602.          */
  603.         tellUserNoZones();
  604.     }
  605.     StopAnimatedCursors();
  606. }
  607.  
  608.  
  609. void processListUpdate()
  610. {
  611.     Str255    tempStr, errorStr;
  612.     
  613.     if (OpenTransportActive())
  614.     {
  615.         ProcessOTListUpdate((char *)tempStr);
  616.     }
  617.     else
  618.     {
  619.         if(gPBLkUP->myMPP.MPPioResult >= noErr) 
  620.         {
  621.             NumToString((long) gPBLkUP->myMPP.NBPnumGotten, tempStr);
  622.             Pstrcat(tempStr, "\p items");
  623.         
  624.             SetObjectTypeCells(gBuffPtr, gPBLkUP->myMPP.NBPnumGotten);
  625.         }
  626.         else 
  627.         {
  628.             NumToString((long) gPBLkUP->myMPP.MPPioResult, errorStr);
  629.             tempStr[0] = 0;
  630.             Pstrcat(tempStr, "\pErr = ");
  631.             Pstrcat(tempStr, errorStr);
  632.         }
  633.     }
  634.     
  635.     gUpdateListFlag = false;
  636.     gLookupFinished = true;
  637.     StopAnimatedCursors();
  638.     
  639.     /* nil out specified text in dialog box since we're done looking */
  640.     if (OpenTransportActive())
  641.         ParamText("\p", "\p", "\p", "\pOT active");
  642.     else
  643.         ParamText("\p", "\p", "\p", "\p");
  644.  
  645.     setItemString(gMyDialog, (short) kObjectCountID, tempStr);
  646.  
  647.     invalidateItem(kProgressID);
  648.     invalidateItem(kObjectCountID);
  649. }
  650.     
  651.  
  652. /* 
  653.  *    myCompletionRoutine is called to set a global flag which is 
  654.  *    inspected each time through the event loop.  The routine is
  655.  *    used by the asynch lookup call.  When the lookup completes,
  656.  *    the global flag is set telling the program to process the 
  657.  *    lookup replies - sort them per specified order.  For PowerPC
  658.  *    there is no need to set the A5 world as the OS does it for you.
  659.  */
  660.  
  661. #ifdef powerc
  662. void myCompletionRoutine(ParamBlockRec *paramBlock)
  663. {    
  664.     gUpdateListFlag = true;
  665. }
  666. #else
  667. void myCompletionRoutine(ParamBlockRec *paramBlock)
  668. {
  669. #ifndef __MWERKS__
  670. #pragma unused (paramBlock)
  671. #endif
  672.  
  673.     saveThatA5();
  674.     gUpdateListFlag = true;
  675.     restoreThatA5();
  676. }
  677. #endif
  678.     
  679. char giveMeItemValue(short whichItem)
  680.  {
  681.     Rect         r;
  682.     short         kind;
  683.     Handle         h;
  684.     Str255        str;
  685.     long         value;
  686.     
  687.     GetDialogItem(gLookupDialog, whichItem, &kind, &h, &r);
  688.     GetDialogItemText(h, str);
  689.     StringToNum(str, &value);
  690.     
  691.     if(value>255) {
  692.         value = 255L;
  693.         SetDialogItemText(h, "\p255");
  694.         }
  695.     else if(value<0) {
  696.         value = 0L;
  697.         SetDialogItemText(h, "\p0");
  698.         }
  699.     return (short)value;
  700. }
  701.      
  702. void giveMeItemString(short whichItem, Str255 str)
  703. {
  704.     Rect         r;
  705.     short         kind;
  706.     Handle         h;
  707.     
  708.     GetDialogItem(gLookupDialog, whichItem, &kind, &h, &r);
  709.     GetDialogItemText(h, str);
  710. }
  711.      
  712. /* 
  713.  *    getTypesNamesInZone is called to initiate the NBP lookup
  714.  *    request.
  715.  *    used by the asynch lookup call.  When the lookup completes,
  716.  *    the global flag is set telling the program to process the 
  717.  *    lookup replies - sort them per specified order.  For PowerPC
  718.  *    there is no need to set the A5 world as the OS does it for you.
  719.  */
  720. void getTypesNamesInZone(char *NBPZone)
  721. {
  722.     OSErr                 resultCode;
  723.     Str255                 NBPObject, NBPType;
  724.     Str255                tempText;
  725.     Str32                noZoneName = "\pNo zones <*>.";
  726.     Str32                localZone = "\pthe local zone";
  727.     Boolean                localFlag = false;
  728.     static MPPCompletionUPP    gMyCompletionRoutineUPP = nil;
  729.  
  730.     if (((dmzEntryPtr) *(gATQEntry.globs))->atalkActive == false)  // ATalk not active.
  731.         return;    
  732.  
  733.     /*
  734.      * Check whether there are no zones in the zone list
  735.      */
  736.     if (PStrComp(noZoneName, (unsigned char *)gNameGlob)) 
  737.         localFlag = true;
  738.  
  739.     giveMeItemString(kObjectItem, NBPObject);
  740.     giveMeItemString(kTypeItem, NBPType);
  741.     BlockMove(NBPZone, &gNameGlob[0], sizeof(gNameGlob));
  742.         
  743.     if (OpenTransportActive() == true)
  744.     {
  745.         DoOTNameLookup((char *)NBPObject, (char *)NBPType, (char *)NBPZone);
  746.     }
  747.     else
  748.     {
  749.         StartAnimatedCursors(kSpinEvery5Ticks, 15);    
  750.         if (gMyCompletionRoutineUPP==nil)
  751.             gMyCompletionRoutineUPP = NewMPPCompletionProc(myCompletionRoutine);
  752.     
  753.         /* 
  754.          *    oh dang... there may be an NBPLookup already pending.  Kill It first. 
  755.          */
  756.         killLookups();
  757.         
  758.         NBPSetEntity((Ptr)&gLookupNTE.nt.entityData[0], (ConstStr32Param)NBPObject, 
  759.                             (ConstStr32Param)NBPType, (ConstStr32Param)NBPZone);
  760.     
  761.         gPBLkUP->myA5 = (long)LMGetCurrentA5();    /* get the Current A5 */
  762.     
  763.         gLookupFinished = false;
  764.     
  765.         gPBLkUP->myMPP.MPPioCompletion = gMyCompletionRoutineUPP;
  766.         gPBLkUP->myMPP.NBPinterval = giveMeItemValue(kIntervalItem);
  767.         gPBLkUP->myMPP.NBPcount = giveMeItemValue(kCountItem);
  768.         gPBLkUP->myMPP.NBPentityPtr = (Ptr)&gLookupNTE.nt.entityData;
  769.         gPBLkUP->myMPP.NBPretBuffSize =  kLookupBufSize;
  770.         gPBLkUP->myMPP.NBPretBuffPtr = (Ptr) gBuffPtr;
  771.         gPBLkUP->myMPP.NBPmaxToGet =  kLookupBufSize / kNBPEntityBufferSize;
  772.     
  773.         resultCode = PLookupName((MPPParamBlock *) &gPBLkUP->myMPP, true);
  774.         if (resultCode == 0)
  775.         {    
  776.             gLookupFinished = true;    
  777.             StopAnimatedCursors();
  778.         }
  779.     }
  780.  
  781.     /* 
  782.      * inform the user of what we are doing 
  783.      *     and zero out current entity count.
  784.      */
  785.     tempText[0] = 0;
  786.     if (localFlag)
  787.         Pstrcat(tempText, localZone);
  788.     else
  789.         Pstrcat(tempText, (unsigned char *)NBPZone);
  790.         
  791.     Pstrcat(tempText, "\p…");
  792.     ParamText("\p", "\p", "\plooking in:", tempText);        
  793.  
  794.     tempText[0] = 0;
  795.     setItemString(gMyDialog, (short) kObjectCountID, tempText);
  796.  
  797.     invalidateItem(kProgressID);
  798.     invalidateItem(kObjectCountID);
  799.  
  800. }
  801.  
  802.  
  803. /* 
  804.  *    GetMyZone function
  805.  */
  806. void doGetMyZonePhs2()
  807. {
  808.     XCallParam    xpb;
  809.     OSErr        resultCode;
  810.     char        myZoneNameBuffer[33];
  811.     short        refNum;
  812.     
  813.     resultCode = OpenDriver("\p.XPP", &refNum);
  814.  
  815.     xpb.ioRefNum = refNum;
  816.     xpb.csCode = xCall;
  817.     xpb.xppSubCode = zipGetMyZone;
  818.     xpb.zipBuffPtr = (Ptr) &myZoneNameBuffer;
  819.     xpb.zipInfoField[0] = 0;    /* ALWAYS 0 */
  820.     resultCode = PBControl((ParmBlkPtr) &xpb, false);
  821. }
  822.  
  823. void doGetLocalZonesPhs2()
  824. {
  825.     XCallParam    xpb;
  826.     OSErr        resultCode = 0;
  827.     Ptr            returnBuffer, theBufferPtr;
  828.     short        refNum;
  829.     short        totalZones = 0;
  830.     
  831.     resultCode = OpenDriver("\p.XPP", &refNum);
  832.  
  833.     returnBuffer = NewPtr(kMaxZoneBuffSize); /* set to max SInt16 */
  834.     
  835.     theBufferPtr = NewPtr(578); /* size of BDS */
  836.     if(MemError()==noErr) {
  837.  
  838.         xpb.zipInfoField[0] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  839.         xpb.zipLastFlag = 0;
  840.  
  841.         xpb.ioRefNum = refNum;
  842.         xpb.csCode = xCall;
  843.         xpb.xppSubCode = zipGetLocalZones;
  844.         xpb.xppTimeout = 3;
  845.         xpb.xppRetry = 4;
  846.         xpb.zipBuffPtr = (Ptr) theBufferPtr;
  847.  
  848.         while(xpb.zipLastFlag == 0 && resultCode == 0) {
  849.  
  850.             resultCode = PBControl((ParmBlkPtr) &xpb, false);
  851.  
  852.             if(resultCode == noErr) {    
  853.                 SpinTheCursor();        
  854.                 addToUnpackedBuffer(theBufferPtr, returnBuffer, xpb.zipNumZones, totalZones);            
  855.                 totalZones += xpb.zipNumZones;
  856.                 }
  857.             }
  858.         
  859.         if(resultCode == noErr)     
  860.             SetZoneCells(returnBuffer, totalZones);
  861.  
  862.         DisposePtr(theBufferPtr);
  863.         DisposePtr(returnBuffer);
  864.         }
  865. }
  866.  
  867. /*
  868.  *    When AppleTalk Phase 2 is present, things go a bit easier.
  869.  */
  870. void doGetZoneListPhs2()
  871. {
  872.     XCallParam    xpb;
  873.     OSErr        resultCode = 0;
  874.     Ptr            returnBuffer, theBufferPtr;
  875.     short        refNum;
  876.     short        totalZones = 0;
  877.         
  878.     resultCode = OpenDriver("\p.XPP", &refNum);
  879.  
  880.     returnBuffer = NewPtr(kMaxZoneBuffSize); /* set to max SInt16 */
  881.     
  882.     theBufferPtr = NewPtr(578); /* size of BDS */
  883.     
  884.     if(MemError()==noErr) {
  885.         xpb.zipInfoField[0] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  886.         xpb.zipInfoField[1] = 0;    /* ALWAYS 0 on first call.  has state info on subsequent calls */
  887.         xpb.zipLastFlag = 0;
  888.         
  889.         xpb.ioRefNum = refNum;
  890.         xpb.csCode = xCall;
  891.         xpb.xppSubCode = zipGetZoneList;
  892.         xpb.xppTimeout = 3;
  893.         xpb.xppRetry = 4;
  894.         xpb.zipBuffPtr = (Ptr) theBufferPtr;
  895.  
  896.         while(xpb.zipLastFlag == 0 && resultCode == 0) {
  897.             resultCode = PBControl((ParmBlkPtr) &xpb, false);
  898.  
  899.             if(resultCode == noErr) {    
  900.                 SpinTheCursor();        
  901.                 addToUnpackedBuffer(theBufferPtr, returnBuffer, xpb.zipNumZones, totalZones);            
  902.                 totalZones += xpb.zipNumZones;
  903.                 }
  904.             }
  905.         /*
  906.          *    If all went well, add zone names to our list.
  907.          */
  908.          if(resultCode == noErr)     
  909.             SetZoneCells(returnBuffer, totalZones);
  910.  
  911.         /*
  912.          *    Dispose of memory we allocated.
  913.          */
  914.         DisposePtr(theBufferPtr);
  915.         DisposePtr(returnBuffer);
  916.         }
  917. }
  918.  
  919. /*
  920.  *    setupEchoDialog displays the echo packet test results having
  921.  *  processed the return packet.  This dialog displays the results
  922.  *  in terms of hop count to reach the object and seconds required to
  923.  *  "ping" the object.  If an error occurred, it is displayed instead
  924.  */
  925. void setupEchoDialog(DialogPtr echoDialog, myNetworkEntity *myEnt)
  926. {
  927.     short            kind;
  928.     Handle            h;
  929.     Rect            r;
  930.     Str32            noZoneName = "\pNo zones <*>.";
  931.     Str32            localZone = "\plocal zone";
  932.     Boolean            localFlag = false;
  933.     static UserItemUPP    gAboutOKFrameUPP = nil;
  934.     
  935.     if (gAboutOKFrameUPP==nil)
  936.         gAboutOKFrameUPP = NewUserItemProc(aboutDialogOKFrame);
  937.  
  938.     GetDialogItem(echoDialog, 10, &kind, &h, &r);
  939.     SetDialogItemText(h, (ConstStr255Param)myEnt->object);
  940.  
  941.     GetDialogItem(echoDialog, 11, &kind, &h, &r);
  942.     SetDialogItemText(h, (ConstStr255Param)myEnt->type);
  943.  
  944.     GetDialogItem(echoDialog, 12, &kind, &h, &r);
  945.     if (PStrComp(noZoneName, (unsigned char *)gNameGlob)) 
  946.         SetDialogItemText(h, localZone);
  947.     else
  948.         SetDialogItemText(h, (ConstStr255Param)gNameGlob);
  949.  
  950.     /* 
  951.      *    set up the userItem proc for the "OK" button outline 
  952.      */
  953.     GetDialogItem(echoDialog, 13, &kind, &h, &r);
  954.     SetDialogItem(echoDialog, 13, userItem, (Handle) gAboutOKFrameUPP, &r);
  955. }
  956.  
  957.  
  958. /*
  959.  *    doEcho is called when the user double clicks on some item indicating
  960.  *  to send an echo packet to the echo socket on the node of that item.
  961.  *  Note all of the preparation which is performed in order to "ping" the
  962.  *  object.  Note that the socket listener code has been implemented as 
  963.  *  a code resource so that for PowerPC we can make a mixed mode call to it.
  964.  
  965.  */
  966. void doEcho(myNetworkEntity    *myEnt)
  967. {
  968.     MPPParamBlock     myMPP;
  969.     OSErr            err;
  970.     Boolean            gotEcho = false;
  971.     WDSElement        myWDS[3];    /* minimum of 3 WDS elements in a Write Data Structure */
  972.     Ptr                gHdrPtr;
  973.     Ptr                myBuffer;
  974.     long            myTicks, myWaitTicks, startTicks, stopTicks;
  975.     unsigned char    myHops;
  976.     DialogPtr        echoDialog;
  977.     Str255            str;
  978.     short            kind;
  979.     Handle            h;
  980.     Rect            r;
  981.     short            itemHit;
  982.     AddrBlock         destAddress;
  983.     long            tempL;
  984.     GrafPtr            savedPort;
  985.     PacketPtr        bufPtr;
  986.         
  987.     GetPort(&savedPort);
  988.  
  989.     StartAnimatedCursors(kSpinEvery5Ticks, 15);
  990.  
  991.     StringToNum((StringPtr) myEnt->net, (long *) &tempL);
  992.     destAddress.aNet = tempL;
  993.     StringToNum((StringPtr) myEnt->node, (long *) &tempL);
  994.     destAddress.aNode = tempL;
  995.     StringToNum((StringPtr) myEnt->socket, (long *) &tempL);
  996.     destAddress.aSocket = tempL;
  997.  
  998.     echoDialog = GetNewDialog(131, 0L, (WindowPtr) -1L);
  999.     SetPort(echoDialog);
  1000.     
  1001.     TextFont(geneva);
  1002.     TextSize(9);
  1003.     
  1004.     setupEchoDialog(echoDialog, myEnt);
  1005.     
  1006.     myMPP.DDPlistener = (DDPSocketListenerUPP) *gSockCodeHndl;
  1007.  
  1008.     myMPP.DDPsocket = 0;
  1009.     err = POpenSkt(&myMPP, false);
  1010.     
  1011.     gHdrPtr = NewPtr(17);                 /* max header size */
  1012.     
  1013.     destAddress.aSocket = 4;             /* Echoer socket */
  1014.     myBuffer = NewPtr(ddpMaxData);
  1015.     *myBuffer = 1;                        /* tell their Echoer we want a reply with a 1 in the first byte */
  1016.     
  1017.     BuildDDPwds((Ptr) &myWDS, gHdrPtr, myBuffer, destAddress, kEchoSocket, ddpMaxData);
  1018.     
  1019.     myMPP.DDPchecksumFlag = true;
  1020.     myMPP.DDPwdsPointer = (Ptr) &myWDS;
  1021.     
  1022.     startTicks = TickCount();            /* start the timer! */
  1023.     
  1024.     err = PWriteDDP(&myMPP, false);
  1025.  
  1026.     myWaitTicks = TickCount() + 600L;    /* wait 10 seconds for reply */
  1027.     
  1028.     while(myWaitTicks > TickCount() && !gUsedQ.qHead)
  1029.     {
  1030.         SpinTheCursor();
  1031.     }
  1032.     
  1033.     if(gUsedQ.qHead) {
  1034.         bufPtr = (PacketPtr)gUsedQ.qHead;    /* get the packet ptr */
  1035.                         /* we could check the DDP type in the buffer_type field
  1036.                          * but we leave it as an exercise to the reader.  
  1037.                          * Note that the way the gUsedQ is structured so that 
  1038.                          * we could check whether the packet is for us, or for 
  1039.                          * some other process which utilizes the same listener.  
  1040.                          * In the next step we dequeue the packet so that it 
  1041.                          * doesn't get overwritten */
  1042.         if (Dequeue((QElemPtr)gUsedQ.qHead, &gUsedQ) == noErr) {
  1043.             if (bufPtr->buffer_CheckSum != noErr)
  1044.             {
  1045.                 GetDialogItem(echoDialog, 6, &kind, &h, &r);
  1046.                 SetDialogItemText(h, "\pWah…Checksum error occurred");
  1047.             }
  1048.             else
  1049.             {
  1050.                 stopTicks = bufPtr->buffer_Ticks;
  1051.                 myTicks = stopTicks - startTicks;
  1052.         
  1053.                 GetDialogItem(echoDialog, 4, &kind, &h, &r);
  1054.                 myHops = bufPtr->buffer_Hops;
  1055.                 NumToString((long) myHops, (void *) &str);
  1056.                 SetDialogItemText(h, str);
  1057.             
  1058.                 GetDialogItem(echoDialog, 5, &kind, &h, &r);
  1059.                 NumToString(myTicks, (void *) &str);
  1060.                 SetDialogItemText(h, str);
  1061.             }
  1062.                                         /* requeue the packet buffer for use. */
  1063.             Enqueue((QElemPtr)bufPtr, &gFreeQ);
  1064.         }
  1065.         else {
  1066.             GetDialogItem(echoDialog, 6, &kind, &h, &r);
  1067.             SetDialogItemText(h, "\pWah… packet Dequeue error occured");
  1068.         }
  1069.     }
  1070.     else {
  1071.         GetDialogItem(echoDialog, 6, &kind, &h, &r);
  1072.         SetDialogItemText(h, "\pWah… no echo reply received!");
  1073.     }
  1074.     /* clean up memory allocations */
  1075.     DisposePtr(gHdrPtr);
  1076.     DisposePtr(myBuffer);
  1077.     err = PCloseSkt(&myMPP, false);    
  1078.     
  1079.     /* report the results */
  1080.     centerDialog((WindowPtr) echoDialog);
  1081.  
  1082.     StopAnimatedCursors();
  1083.  
  1084.     InitCursor();
  1085.     ShowWindow(echoDialog);
  1086.     
  1087.     ModalDialog(0L, &itemHit);
  1088.     DisposeDialog(echoDialog);
  1089.     
  1090.     SetPort(savedPort);
  1091. }
  1092.  
  1093.  
  1094. /*
  1095.  *    Here's our AppleTalk Transition Queue handler - we just want
  1096.  *  to know if the user shuts down AppleTalk, or changes connections
  1097.  *  and do the right thing like deregister our NBP name.  On entry 
  1098.  *  the current A5 world gets saved under 68K and set to that of
  1099.  *  our application.  We can then make calls to the program and
  1100.  *  use program globals.
  1101.  */
  1102.  
  1103. long ATalkTransQueue(long selector, myATQEntry *q, void *p)
  1104. {
  1105. #pragma unused (p)
  1106.     long                returnVal = 0; /* return 0 for unrecognized events */
  1107.     dmzEntryPtr            dmzPtr;
  1108.     long                a5Save;
  1109.         
  1110.     //DebugStr("\pEntering ATQ");
  1111.  
  1112. #ifndef    powerc
  1113.     /* set a5 to that for the app */
  1114.     a5Save = SetA5(q->myA5);
  1115. #endif
  1116.     /*
  1117.      * This is the dispatch part of the routine. We'll check the selector passed into
  1118.      * the task; its location is 4 bytes off the stack (selector).
  1119.      */
  1120.  
  1121.     dmzPtr = (dmzEntryPtr)*(q->globs);
  1122.     switch(selector) {
  1123.         case ATTransOpen:
  1124.             /*
  1125.              *  Someone has opened the .MPP driver. Set Flag to re-initialize AppleTalk portion of pgm
  1126.              */
  1127.              
  1128.             dmzPtr->atalkStatusChanged = true;
  1129.             dmzPtr->atalkActive = true;            
  1130.             break;
  1131.             
  1132.         case ATTransClose:
  1133.             /*
  1134.              *  .MPP is going to shut down no matter what we do.  Call Cleanup routine
  1135.              */
  1136.  
  1137.             removeMyNameAndSocket();
  1138.             
  1139.             dmzPtr->atalkStatusChanged = true;
  1140.             dmzPtr->atalkActive = false;            
  1141.             break;
  1142.  
  1143.  
  1144.         case ATTransClosePrep:
  1145.             /*
  1146.              *  .MPP is asking whether it can shut down.  
  1147.              */
  1148.  
  1149.             break;
  1150.             
  1151.     } /* end of switch */
  1152.     
  1153.     /* 
  1154.      *    return value in register D0 
  1155.      */
  1156. #ifndef    powerc
  1157.     SetA5(a5Save);
  1158. #endif
  1159.     return returnVal;
  1160. }
  1161.  
  1162. /*
  1163.  *    This routine loads the socket listener code and initializes the buffers to 
  1164.  *  be used by the socket listener code. A check is made to determine whether VM
  1165.  *  is active and to hold the memory associated with buffers that might be 
  1166.  *  critical to the operation of the socket listener.  We load the socket 
  1167.  *  socket listener code resource and lock it in memory.
  1168.  */
  1169.  
  1170. OSErr InitEchoBuffers(void)
  1171. {
  1172.     OSErr            err = noErr;
  1173.     short            i;
  1174.     Size            listenerSize;
  1175.     
  1176.     /* check whether the buffers have already been init'd */
  1177.  
  1178.     if (!(TstSocketBuffsInitdFlag(gATalkFlags))) {
  1179.         /* set up the free and used queues */
  1180.         gFreeQ.qFlags = 0;
  1181.         gFreeQ.qHead = nil;
  1182.         gFreeQ.qTail = nil;
  1183.         
  1184.         gUsedQ.qFlags = 0;
  1185.         gUsedQ.qHead = nil;
  1186.         gUsedQ.qTail = nil;
  1187.         
  1188.         /* enqueue the packet buffer records to the free queue */
  1189.         for (i=0; i<kNumBuffers; i++, gFreeQ.qFlags ++)
  1190.             Enqueue((QElemPtr)&gBuffers[i], &gFreeQ);
  1191.         
  1192.         /* show that the buffers have been init'd */
  1193.         SetSocketBuffsInitdFlag(gATalkFlags);
  1194.         
  1195.         /* check whether VM is on and hold the packet buffers */
  1196.         if (TstVMActiveFlag(gATalkFlags)) 
  1197.         {
  1198.  
  1199.             err = HoldMemory(&gBuffers, sizeof(gBuffers));
  1200.             if (err == noErr)  {
  1201.                 /* mark queue structures for hold */
  1202.                 HoldMemory(&gFreeQ, sizeof(QHdr));
  1203.                 HoldMemory(&gUsedQ, sizeof(QHdr));
  1204.                 /* set the global ATalkFlags to reflect the held memory */
  1205.                 SetSocketBuffsHeldFlag(gATalkFlags);
  1206.             }
  1207.         }
  1208.                 
  1209.         /*********** get socket listener code **********/
  1210.         if ((gSockCodeHndl == nil) && (OpenTransportActive() == false))
  1211.         {
  1212.             gSockCodeHndl = Get1Resource('Sock',128);
  1213.             if (gSockCodeHndl==nil)
  1214.                 return (resNotFound);
  1215.             MoveHHi(gSockCodeHndl);
  1216.             HLock(gSockCodeHndl);
  1217.             
  1218.             /* tell the socket listener about the 2 queues */
  1219.             err = CallInitSktListenerProc(((InitSktListenerProcPtr)((long) *gSockCodeHndl + 2)), &gFreeQ, &gUsedQ);
  1220.  
  1221.         /*********** end get socket listener code **********/
  1222.  
  1223.             if (err == noErr) {
  1224.                 if (TstVMActiveFlag(gATalkFlags)) 
  1225.                 {
  1226.                     listenerSize = GetHandleSize(gSockCodeHndl);
  1227.     
  1228.                     err = HoldMemory(*gSockCodeHndl, listenerSize);
  1229.                     if (err == noErr)
  1230.                         SetListenerHeldFlag(gATalkFlags);
  1231.                 }
  1232.             }
  1233.             if (err)
  1234.                 BigBadError("\pSocket listener init failed - aborting program");
  1235.                 /* I guess we could fail the use of the socket listener
  1236.                  * instead of aborting the program however, that is left as an
  1237.                  * exercise to the user
  1238.                  */
  1239.         }
  1240.         
  1241.     }
  1242.     return(err);
  1243.  
  1244. }
  1245.  
  1246. Boolean GestaltAvailable(void)
  1247. {
  1248.     return (TrapAvailable(_Gestalt));
  1249. }
  1250.  
  1251.  
  1252. short AppleTalkVersion(void)
  1253. {
  1254.     short         versionRequested = 1; /* version of SysEnvRec */
  1255.     short        refNum;
  1256.     long        attrib;
  1257.     short        atlkVer;
  1258.  
  1259.     atlkVer = 0;    /* default to no AppleTalk */
  1260.     if (GestaltAvailable())            /* check whether Gestalt is available */
  1261.     {
  1262.         if (Gestalt('atkv', &attrib) == noErr)    /* check the atkv selector which */
  1263.         {                                        /* return ATalk version regardless whether */
  1264.                                                 /* ATalk is on or off */
  1265.             atlkVer = attrib >> 24;
  1266.         }
  1267.         else if (OpenDriver("\p.MPP", &refNum) == noErr)    /* open, then check the 'atlk' */
  1268.         {                                        /* selector to get ATalk version */
  1269.             if (Gestalt(gestaltAppleTalkVersion, &attrib) == noErr)
  1270.                 atlkVer = attrib & 0x000000FF;
  1271.         }
  1272.     }
  1273.     return atlkVer;
  1274. }
  1275.  
  1276.  
  1277. Boolean LAPMgrExists(void)
  1278. {    
  1279.     return (AppleTalkVersion() >= 53);
  1280. }
  1281.